/*
 * @(#)InitiatingQueryService.java
 * Date 2013-10-24
 * Version 1.0
 * Author Jim Horner
 * Copyright (c)2012
 */


package us.hornerscorners.lamppost.xca.service;

import javax.annotation.PostConstruct;

import javax.enterprise.context.ApplicationScoped;

import javax.inject.Inject;

import ihe.iti.xds_b._2007.RespondingGatewayQueryService;

import oasis.names.tc.ebxml_regrep.xsd.query._3.AdhocQueryRequest;
import oasis.names.tc.ebxml_regrep.xsd.query._3.AdhocQueryResponse;

import oasis.names.tc.ebxml_regrep.xsd.rim._3.RegistryObjectListType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import us.hornerscorners.lamppost.atna.client.utils.AtnaUtils;

import us.hornerscorners.lamppost.config.EndpointConfig;

import us.hornerscorners.lamppost.exception.ServiceActionError;
import us.hornerscorners.lamppost.exception.ServiceActionException;
import us.hornerscorners.lamppost.exception.SeverityType;

import us.hornerscorners.lamppost.ihecommon.config.IHEConfig;
import us.hornerscorners.lamppost.ihecommon.config.IHEServiceType;
import us.hornerscorners.lamppost.ihecommon.config.RespondingGatewayConfig;
import us.hornerscorners.lamppost.ihecommon.config.XCAGatewayConfig;

import us.hornerscorners.lamppost.model.audit.AuditContext;
import us.hornerscorners.lamppost.model.audit.CodedValueType;

import us.hornerscorners.lamppost.registry.constant.ErrorCode;
import us.hornerscorners.lamppost.registry.constant.ResponseStatus;

import us.hornerscorners.lamppost.registry.inject.RegistryTarget;

import us.hornerscorners.lamppost.registry.service.AtnaRegistryService;
import us.hornerscorners.lamppost.registry.service.IStoredQueryService;
import us.hornerscorners.lamppost.registry.service.SimpleXDSParser;

import us.hornerscorners.lamppost.registry.transformer.xds
    .RegistryResponseTypeTransformer;

import us.hornerscorners.lamppost.xca.client.RespondingQueryClient;


/**
 * Class description
 *
 *
 * @version        v1.0, 2013-10-24
 * @author         Jim Horner
 */
@ApplicationScoped
public class InitiatingQueryService implements IStoredQueryService {

    /** Field description */
    @Inject
    private AtnaRegistryService atnaService;

    /** Field description */
    @Inject
    private IHEConfig config;

    /** Field description */
    private final Logger logger = LoggerFactory.getLogger(getClass());

    /** Field description */
    private final RespondingGatewayQueryService queryService;

    /** Field description */
    @Inject
    @RegistryTarget
    private RegistryResponseTypeTransformer registryResponseTransformer;

    /** Field description */
    private XCAGatewayConfig serviceConfig;

    /**
     * Constructs ...
     *
     */
    public InitiatingQueryService() {

        super();

        this.queryService = new RespondingGatewayQueryService();
    }

    /**
     * Method description
     *
     *
     * @param body
     *
     * @return
     */
    @Override
    public AdhocQueryResponse executeStoredQuery(AuditContext auditContext,
            AdhocQueryRequest body) {

        AdhocQueryResponse result = new AdhocQueryResponse();

        try {

            String homeCommunityId = body.getAdhocQuery().getHome();
            EndpointConfig endpointConfig = findServiceEndpoint(homeCommunityId);

            RespondingQueryClient client = new RespondingQueryClient(this.atnaService,
                                               this.queryService, endpointConfig);

            CodedValueType eventType = AtnaUtils.createCodedValue("ITI-38",
                                           "IHE Transactions", "Cross Gateway Query");

            AuditContext queryContext = new AuditContext(eventType,
                                            this.config.getClientConfig(),
                                            auditContext.getTransactionContext(),
                                            auditContext.getAddressContext());

            result = client.executeStoredQuery(queryContext, body);

        } catch (ServiceActionException e) {

            logger.error(e.getMessage(), e);
            result.setRegistryObjectList(new RegistryObjectListType());
            result.setStatus(ResponseStatus.Failure.getCode());
            result.setRegistryErrorList(
                this.registryResponseTransformer.createRegistryErrorList(e));

        } finally {

            this.atnaService.sendQueryReceivedAuditMessage(auditContext, body, result);
        }

        return result;
    }

    /**
     * Method description
     *
     *
     * @param homeCommunityId
     *
     * @return
     */
    private EndpointConfig findServiceEndpoint(String homeCommunityId)
            throws ServiceActionException {

        RespondingGatewayConfig gatewayConfig =
            this.serviceConfig.findRespondingGateway(homeCommunityId);

        if (gatewayConfig == null) {

            String msg = String.format("AdhocQuery homeCommunityId [%s] is not valid.",
                                       homeCommunityId);

            throw new ServiceActionException(
                getClass(),
                new ServiceActionError(
                    ErrorCode.XDSUnknownCommunity.getCode(), msg, SeverityType.Error));
        }

        EndpointConfig result =
            this.config.findServiceEndpoint(gatewayConfig.getQueryServiceId());

        if (result == null) {

            String msg =
                String.format(
                    "AdhocQuery homeCommunityId [%s] query service endpoint is not configured.",
                    homeCommunityId);

            throw new ServiceActionException(
                getClass(),
                new ServiceActionError(
                    ErrorCode.XDSUnknownCommunity.getCode(), msg, SeverityType.Error));
        }

        return result;
    }

    /**
     * Method description
     *
     */
    @PostConstruct
    public void postConstruct() {

        this.serviceConfig =
            (XCAGatewayConfig) this.config.findServiceConfig(IHEServiceType.XCA);
    }
}
